home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / progutil / stdwin.zoo / vt / vt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-18  |  14.6 KB  |  660 lines

  1. /* Virtual Terminal -- basic output routines */
  2. /* $Header: vt.c,v 1.6 88/06/20 22:39:25 guido Exp $ */
  3.  
  4. #include "vtimpl.h"
  5.  
  6. #ifdef macintosh
  7. /* Bold mode uses the "Bold" font, found in VersaTerm;
  8.    this matches Monaco and is available only in 9 pt. */
  9. #define DO_BOLD
  10. #define SETBOLD() wsetfont("Bold")
  11. #define SETNORMAL() wsetfont("Monaco")
  12. #endif
  13.  
  14. /* Forward */
  15. void vtdrawproc ARGS((WINDOW *win, int left, int top, int right, int bottom));
  16. void vtdraw ARGS((VT *vt, int r1, int c1, int r2, int c2));
  17. void vtchrange ARGS((VT *vt, int r1, int c1, int r2, int c2));
  18.  
  19. /* Administration for vtfind */
  20.  
  21. static VT **vtlist;    /* Registered VT structs */
  22. static int nvt;        /* Number of registered VT structs */
  23.  
  24. /* Open a VT window of given size */
  25.  
  26. VT *
  27. vtopen(title, rows, cols, save)
  28.     char *title;
  29.     int rows, cols;
  30.     int save; /* Number of rows scroll-back capacity */ 
  31. {
  32.     int row;
  33.     VT *vt= ALLOC(VT);
  34.     
  35.     if (vt == NULL)
  36.         return NULL;
  37.     rows += save;
  38.     vt->rows= rows;
  39.     vt->cols= cols;
  40.     vt->topterm= save;
  41.     vt->cwidth= wcharwidth('0');
  42.     vt->cheight= wlineheight();
  43.     
  44.     vt->llen= NALLOC(short, rows);
  45.     vt->data= NALLOC(char *, rows);
  46.     vt->flags= NALLOC(unsigned char *, rows);
  47.     for (row= 0; row < rows; ++row) {
  48.         if (vt->data != NULL)
  49.             vt->data[row]= NALLOC(char, cols);
  50.         if (vt->flags != NULL)
  51.             vt->flags[row]= NALLOC(unsigned char, cols);
  52.     }
  53.     /* Assume that if one NALLOC fails, all following ones
  54.        for the same size also fail... */
  55.     if (vt->llen == NULL ||
  56.         vt->data == NULL ||
  57.         vt->data[rows-1] == NULL ||
  58.         vt->flags == NULL ||
  59.         vt->flags[rows-1] == NULL) {
  60.         vt->win= NULL;
  61.         vtclose(vt);
  62.         return NULL;
  63.     }
  64.     
  65.     vt->win= wopen(title, vtdrawproc);
  66.     if (vt->win == NULL)
  67.         vtclose(vt);
  68.     wsetdocsize(vt->win, cols * vt->cwidth, rows * vt->cheight);
  69.     
  70.     vt->nlcr= FALSE;
  71.     vt->lazy= FALSE;
  72.     vtreset(vt); /* Clear additional fields */
  73.     L_APPEND(nvt, vtlist, VT *, vt);
  74.     
  75.     return vt;
  76. }
  77.  
  78. /* Close a VT window.
  79.    Also used to clean-up when vtopen failed half-way */
  80.  
  81. void
  82. vtclose(vt)
  83.     VT *vt;
  84. {
  85.     int i, row;
  86.     
  87.     for (i= 0; i < nvt; ++i) {
  88.         if (vt == vtlist[i]) {
  89.             L_REMOVE(nvt, vtlist, VT *, i);
  90.             break;
  91.         }
  92.     }
  93.     
  94.     if (vt->win != NULL)
  95.         wclose(vt->win);
  96.     for (row= 0; row < vt->rows; ++row) {
  97.         if (vt->data != NULL)
  98.             FREE(vt->data[row]);
  99.         if (vt->flags != NULL)
  100.             FREE(vt->flags[row]);
  101.     }
  102.     FREE(vt->data);
  103.     FREE(vt->flags);
  104.     FREE(vt);
  105. }
  106.  
  107. /* Output a string to a VT window.
  108.    This does not do escape sequence parsing or control character
  109.    interpretation, but honors the 'modes' the VT can be in
  110.    (insert, inverse/underline etc.) and the scrolling region.
  111.    It updates the cursor position and scrolls if necessary.
  112.    Note that after one or more calls to vtputstring it is necessary
  113.    to call vtsync(vt)! */
  114.  
  115. void
  116. vtputstring(vt, text, len)
  117.     VT *vt;
  118.     char *text;
  119.     int len;
  120. {
  121.     int row= vt->cur_row;
  122.     int col= vt->cur_col;
  123.     short *llen= vt->llen;
  124.     int scr_top= (vt->scr_top == vt->topterm) ? 0 : vt->scr_top;
  125.     int scr_bot= (vt->cur_row >= vt->scr_bot) ? vt->rows : vt->scr_bot;
  126.     int wrap= 0; /* Number of times wrapped around */
  127.     
  128.     /* Compute text length if necessary */
  129.     
  130.     if (len < 0)
  131.         len= strlen(text);
  132.     
  133.     /* This is a 'do' loop so that a call with an empty
  134.        string will still normalize the cursor position */
  135.     
  136.     do {
  137.         int llen_row, n, oldcol;
  138.         
  139.         /* Normalize the cursor position.
  140.            When we get past the bottom edge we must scroll,
  141.            but the actual scrolling is delayed until later:
  142.            here we just wrap around and remember how many
  143.            times we've wrapped.
  144.            Thus, scrolling multiple lines is effected as
  145.            a 'jump' scroll up -- not so nice-looking,
  146.            but essential with current performance limitations
  147.            of bitblt hardware.
  148.            When faster machines become available we may need
  149.            an option to turn this optimization off in favour
  150.            of smooth scrolling. */
  151.         
  152.         if (col >= vt->cols) {
  153.             col= 0;
  154.             ++row;
  155.             if (wrap > 0 && row < scr_bot)
  156.                 llen[row]= 0;
  157.         }
  158.         if (row >= scr_bot) {
  159.             /* Should only do this if vt->lazy... */
  160.             ++wrap;
  161.             row= scr_top;
  162.             llen[row]= 0;
  163.         }
  164.         oldcol= col; /* For vtdraw call below */
  165.         
  166.         /* If the cursor is beyond the current line length,
  167.            pad with space.
  168.            Set llen_row to the new line length. */
  169.         
  170.         llen_row= llen[row];
  171.         if (llen_row < col) {
  172.             do {
  173.                 vt->data[row][llen_row]= ' ';
  174.                 vt->flags[row][llen_row]= 0;
  175.             } while (++llen_row < col);
  176.         }
  177.         
  178.         /* Set n to the number of characters that can be
  179.            inserted in the current line */
  180.         
  181.         n= vt->cols - col;
  182.         CLIPMAX(n, len);
  183.         
  184.         /* When inserting, shift the rest of the line right.
  185.            The last characters may fall of the edge. */
  186.         
  187.         if (vt->insert && llen_row > col && col+n < vt->cols) {
  188.             int k;
  189.             llen_row += n;
  190.             CLIPMAX(llen_row, vt->cols);
  191.             vtscroll(vt, row, col, row+1, llen_row, 0, n);
  192.             for (k= llen_row - n; --k >= col; ) {
  193.                 vt->data[row][k+n]= vt->data[row][k];
  194.                 vt->flags[row][k+n]= vt->flags[row][k];
  195.             }
  196.         }
  197.         
  198.         /* Copy the characters into the line data */
  199.         
  200.         strncpy(vt->data[row] + col, text, (size_t)n);
  201.         
  202.         /* Update loop administration, maintaining the invariant:
  203.            'len' characters starting at 'text' still to do */
  204.         
  205.         len -= n;
  206.         text += n;
  207.         
  208.         /* Set the corresponding flag bits.
  209.            The current column is set as a side effect. */
  210.         
  211.         while (--n >= 0)
  212.             vt->flags[row][col++]= vt->gflags;
  213.         
  214.         /* Update line length */
  215.         
  216.         CLIPMIN(llen_row, col);
  217.         llen[row]= llen_row;
  218.         
  219.         /* Maybe draw the characters now */
  220.         
  221.         if (!vt->lazy) {
  222.             wbegindrawing(vt->win);
  223.             vtdraw(vt, row, oldcol, row+1, col);
  224.             wenddrawing(vt->win);
  225.             vtsetcursor(vt, row, col);
  226.         }
  227.         
  228.         /* Loop while more work to do */
  229.         
  230.     } while (len > 0);
  231.     
  232.     /* Process delayed scrolling. */
  233.     
  234.     if (wrap > 0) {
  235.         /* Yes, we need to scroll.
  236.            When wrap > 1, we have scrolled more than a screenful;
  237.            then the vtscroll call is skipped, but we must still
  238.            circulate the lines internally. */
  239.         
  240.         /* Picture:
  241.            
  242.            scr_top ___________________ (first line affected)
  243.               .    ___________________
  244.               .    ______ row ________
  245.               .    ___________________ (last line affected)
  246.            scr_bot
  247.            
  248.            Data move: circulate down so that the data at row
  249.            moves to scr_bot - 1.
  250.            Screen bits move: the line below row must
  251.            become scr_top.
  252.            We must also invalidate the characters changed
  253.            before we started scrolling, but we must do this
  254.            after the vtscroll call, because some STDWIN
  255.            versions don't properly scroll invalidated bits.
  256.         */
  257.         
  258.         if (row + 1 != scr_bot) {
  259.             vtcirculate(vt,
  260.                 scr_top, scr_bot,
  261.                 scr_bot - (row + 1));
  262.         }
  263.         if (wrap == 1) {
  264.             int n= (row + 1) - scr_top;
  265.             vtscroll(vt, scr_top, 0, scr_bot, vt->cols, -n, 0);
  266.             /* Invalidate old pos through end */
  267.             vtchrange(vt,
  268.                 vt->cur_row - n, vt->cur_col,
  269.                 scr_bot - 1, vt->cols);
  270.         }
  271.         else
  272.             vtchange(vt, scr_top, 0, scr_bot, vt->cols);
  273.         row= scr_bot - 1;
  274.     }
  275.     else {
  276.         vtchrange(vt, vt->cur_row, vt->cur_col, row, col);
  277.     }
  278.     
  279.     /* Set the new cursor position */
  280.     
  281.     vtsetcursor(vt, row, col);
  282. }
  283.  
  284. /* Subroutine to change the text range from (r1, c1) to (r2, c2).
  285.    This is not the same as vtchange; this function deals with text
  286.    ranges, while vtchange deals with rectanlges. */
  287.  
  288. static void
  289. vtchrange(vt, r1, c1, r2, c2)
  290.     VT *vt;
  291. {
  292.     if (r1 >= r2) {
  293.         vtchange(vt, r1, c1, r2+1, c2);
  294.     }
  295.     else {
  296.         vtchange(vt, r1, c1, r1+1, vt->cols);
  297.         vtchange(vt, r1+1, 0, r2, vt->cols);
  298.         vtchange(vt, r2, 0, r2+1, c2);
  299.     }
  300. }
  301.  
  302. /* Set cursor position.
  303.    This sets the STDWIN text caret and calls wshow for the character
  304.    at the cursor.
  305.    The cursor position is clipped to the screen dimensions,
  306.    but it may sit on the right edge just beyond the last character. */
  307.  
  308. void
  309. vtsetcursor(vt, row, col)
  310.     VT *vt;
  311.     int row, col;
  312. {
  313.     CLIPMAX(row, vt->rows - 1);
  314.     CLIPMIN(row, 0);
  315.     CLIPMAX(col, vt->cols);
  316.     CLIPMIN(col, 0);
  317.     vt->cur_row= row;
  318.     vt->cur_col= col;
  319.     wsetcaret(vt->win, col * vt->cwidth, row * vt->cheight);
  320.     CLIPMAX(col, vt->cols - 1);
  321.     vtshow(vt, row, col, row+1, col+1);
  322. }
  323.  
  324. /* Set scrolling region.  Lines in [top...bot) can scroll.
  325.    If the parameters are valid, set the region and move to (0, 0);
  326.    if there is an error, reset the region and don't move.
  327.    (NB: the move is to (0, 0), not to the top of the region!) */
  328.  
  329. void
  330. vtsetscroll(vt, top, bot)
  331.     VT *vt;
  332.     int top, bot;
  333. {
  334.     vtsync(vt);
  335.     if (top >= vt->topterm && top < bot && bot <= vt->rows) {
  336.         vt->scr_top= top;
  337.         vt->scr_bot= bot;
  338.         vtsetcursor(vt, vt->topterm, 0);
  339.         /* vtshow(vt, vt->topterm, 0, vt->rows, vt->cols); */
  340.     }
  341.     else {
  342.         vt->scr_top= vt->topterm;
  343.         vt->scr_bot= vt->rows;
  344.     }
  345.     vtshow(vt, vt->scr_top, 0, vt->scr_bot, vt->cols);
  346. }
  347.  
  348. /* Major reset */
  349.  
  350. void
  351. vtreset(vt)
  352.     VT *vt;
  353. {
  354.     int row;
  355.     
  356.     vtchange(vt, 0, 0, vt->rows, vt->cols);
  357.     vtshow(vt, vt->topterm, 0, vt->rows, vt->cols);
  358.     
  359.     for (row= 0; row < vt->rows; ++row)
  360.         vt->llen[row]= 0;
  361.     
  362.     vt->toscroll= 0;
  363.     vtsetflags(vt, 0);
  364.     vtsetinsert(vt, FALSE);
  365.     vtsetscroll(vt, 0, 0);
  366.     vtsetcursor(vt, vt->topterm, 0);
  367.     vt->save_row= vt->save_col= 0;
  368.     vt->action= NULL; /* This invalidates all other  parsing fields */
  369. }
  370.  
  371. /* Draw procedure */
  372.  
  373. static void
  374. vtdrawproc(win, left, top, right, bottom)
  375.     WINDOW *win;
  376.     int left, top, right, bottom;
  377. {
  378.     VT *vt= vtfind(win);
  379.  
  380.     if (vt != NULL) {
  381.         int cw= vt->cwidth;
  382.         int ch= vt->cheight;
  383.         int col1= left / cw;
  384.         int col2= (right + cw - 1) / cw;
  385.         int row1= top / ch;
  386.         int row2= (bottom + ch - 1) / vt->cheight;
  387.     
  388.         vtdraw(vt, row1, col1, row2, col2);
  389.     }
  390. }
  391.  
  392. static void
  393. vtdraw(vt, row1, col1, row2, col2)
  394.     VT *vt;
  395.     int row1, col1, row2, col2;
  396. {
  397.     int cw= vt->cwidth;
  398.     int ch= vt->cheight;
  399.     register unsigned char cur_flags= 0;
  400.     unsigned char cur_bold= 0;
  401.     int row;
  402.     
  403.     CLIPMIN(col1, 0);
  404.     CLIPMAX(col2, vt->cols);
  405.     CLIPMIN(row1, 0);
  406.     CLIPMAX(row2, vt->rows);
  407.     
  408.     /*
  409.     werase(col1*cw, row1*ch, col2*cw, row2*ch);
  410.     */
  411.     
  412.     for (row= row1; row < row2; ++row) {
  413.         register int col;
  414.         char *data_row= vt->data[row] + col1;
  415.         register unsigned char *flags_row= vt->flags[row] + col1;
  416.         int h= col1*cw;
  417.         int v= row*ch;
  418.         int first= col1;
  419.         register int last= vt->llen[row];
  420.         CLIPMAX(last, col2);
  421.         for (col= first; col < last; ++col) {
  422.             if (*flags_row++ != cur_flags) {
  423.                 int n= col-first;
  424.                 if (n > 0) {
  425.                     wdrawtext(h, v, data_row, n);
  426.                     first= col;
  427.                     data_row += n;
  428.                     h += n*cw;
  429.                 }
  430.                 cur_flags= flags_row[-1];
  431.                 wsetplain();
  432.                 if (cur_flags & VT_UNDERLINE)
  433.                     wsetunderline();
  434.                 if (cur_flags & VT_INVERSE)
  435.                     wsetinverse();
  436. #ifdef DO_BOLD
  437.                 if ((cur_flags & VT_BOLD) != cur_bold) {
  438.                     cur_bold= cur_flags & VT_BOLD;
  439.                     if (cur_bold)
  440.                         SETBOLD();
  441.                     else
  442.                         SETNORMAL();
  443.                 }
  444. #endif
  445.             }
  446.         }
  447.         if (col > first)
  448.             wdrawtext(h, v, data_row, col-first);
  449.     }
  450.     if (cur_flags != 0) {
  451.         wsetplain();
  452. #ifdef DO_BOLD
  453.         if (cur_bold)
  454.             SETNORMAL();
  455. #endif
  456.     }
  457. }
  458.  
  459. /* Find the VT corresponding to a WINDOW */
  460.  
  461. VT *
  462. vtfind(win)
  463.     WINDOW *win;
  464. {
  465.     int i;
  466.     for (i= 0; i < nvt; ++i) {
  467.         if (vtlist[i]->win == win)
  468.             return vtlist[i];
  469.     }
  470.     return NULL;
  471. }
  472.  
  473. /* Subroutine to circulate lines.
  474.    For i in r1 ... r2-1, move line i to position i+n (modulo r2-r1).
  475.  
  476.    For ABS(n)==1, we have a fast solution that always works.
  477.    For larger n, we have a slower solution allocating a temporary buffer;
  478.    if we can't, we repeat the fast solution ABS(n) times (really slow).
  479.    
  480.    We assume reasonable input:
  481.     0 <= r1 < r2 <= vt->rows,
  482.     0 < abs(n) < r2-r1.
  483. */
  484.  
  485. void
  486. vtcirculate(vt, r1, r2, n)
  487.     register VT *vt;
  488.     int r1, r2;
  489.     int n;
  490. {
  491.     if (n == -1) { /* Fast solution, move 1 up */
  492.         char *tdata= vt->data[r1];
  493.         unsigned char *tflags= vt->flags[r1];
  494.         short tllen= vt->llen[r1];
  495.         register int i;
  496.         for (i= r1+1; i < r2; ++i) {
  497.             vt->data[i-1]= vt->data[i];
  498.             vt->flags[i-1]= vt->flags[i];
  499.             vt->llen[i-1]= vt->llen[i];
  500.         }
  501.         vt->data[i-1]= tdata;
  502.         vt->flags[i-1]= tflags;
  503.         vt->llen[i-1]= tllen;
  504.     }
  505.     else if (n == 1) { /* Fast solution, move 1 down */
  506.         char *tdata= vt->data[r2-1];
  507.         unsigned char *tflags= vt->flags[r2-1];
  508.         short tllen= vt->llen[r2-1];
  509.         register int i;
  510.         for (i= r2-1; i > r1; --i) {
  511.             vt->data[i]= vt->data[i-1];
  512.             vt->flags[i]= vt->flags[i-1];
  513.             vt->llen[i]= vt->llen[i-1];
  514.         }
  515.         vt->data[i]= tdata;
  516.         vt->flags[i]= tflags;
  517.         vt->llen[i]= tllen;
  518.     }
  519.     else if (n != 0) {
  520.         if (!slowcirculate(vt, r1, r2, n)) {
  521.             /* Couldn't -- do ABS(n) times the fast case... */
  522.             int step= 1;
  523.             if (n < 0) {
  524.                 n= -n;
  525.                 step= -1;
  526.             }
  527.             while (--n >= 0)
  528.                 vtcirculate(vt, r1, r2, step);
  529.         }
  530.     }
  531. }
  532.  
  533. /* Slow version of the above */
  534.  
  535. static bool
  536. slowcirculate(vt, r1, r2, n)
  537.     register VT *vt;
  538.     int r1, r2;
  539.     int n;
  540. {
  541.     char **tdata= NALLOC(char *, n);
  542.     unsigned char **tflags= NALLOC(unsigned char *, n);
  543.     short *tllen= NALLOC(short, n);
  544.     
  545.     bool ok= tdata != NULL && tflags != NULL && tllen != NULL;
  546.     
  547.     if (ok) {
  548.         register int i;
  549.         r2 -= n;
  550.         for (i= 0; i < n; ++i) {
  551.             tdata[i]= vt->data[r2+i];
  552.             tflags[i]= vt->flags[r2+i];
  553.             tllen[i]= vt->llen[r2+i];
  554.         }
  555.         for (i= r2; --i >= r1; ) {
  556.             vt->data[i+n]= vt->data[i];
  557.             vt->flags[i+n]= vt->flags[i];
  558.             vt->llen[i+n]= vt->llen[i];
  559.         }
  560.         for (i= 0; i < n; ++i) {
  561.             vt->data[r1+i]= tdata[i];
  562.             vt->flags[r1+i]= tflags[i];
  563.             vt->llen[r1+i]= tllen[i];
  564.         }
  565.     }
  566.     
  567.     FREE(tdata);
  568.     FREE(tflags);
  569.     FREE(tllen);
  570.     
  571.     return ok;
  572. }
  573.  
  574. /* VT interface to wchange */
  575.  
  576. void
  577. vtchange(vt, r1, c1, r2, c2)
  578.     VT *vt;
  579.     int r1, c1, r2, c2;
  580. {
  581.     wchange(vt->win,
  582.         c1 * vt->cwidth, r1 * vt->cheight,
  583.         c2 * vt->cwidth, r2 * vt->cheight);
  584. }
  585.  
  586. /* VT interface to wshow */
  587.  
  588. void
  589. vtshow(vt, r1, c1, r2, c2)
  590.     VT *vt;
  591.     int r1, c1, r2, c2;
  592. {
  593.     wshow(vt->win,
  594.         c1 * vt->cwidth, r1 * vt->cheight,
  595.         c2 * vt->cwidth, r2 * vt->cheight);
  596. }
  597.  
  598. /* VT interface to wscroll.
  599.    Sometimes the actual scrolling is postponed by setting vt->toscroll. */
  600.  
  601. void
  602. vtscroll(vt, r1, c1, r2, c2, drow, dcol)
  603.     VT *vt;
  604.     int r1, c1, r2, c2;
  605.     int drow, dcol;
  606. {
  607.     int scr_top= vt->scr_top;
  608.     if (scr_top == vt->topterm)
  609.         scr_top= 0;
  610.     if (vt->lazy && dcol == 0 && r1 == scr_top && r2 == vt->scr_bot &&
  611.         c1 == 0 && c2 == vt->cols) {
  612.         if (drow * vt->toscroll < 0)
  613.             vtsync(vt);
  614.         vt->toscroll += drow;
  615.     }
  616.     else {
  617.         if (vt->toscroll != 0 &&
  618.             r1 < vt->scr_bot && r2 > scr_top)
  619.             vtsync(vt);
  620.         c1 *= vt->cwidth;
  621.         c2 *= vt->cwidth;
  622.         dcol *= vt->cwidth;
  623.         r1 *= vt->cheight;
  624.         r2 *= vt->cheight;
  625.         drow *= vt->cheight;
  626.         wscroll(vt->win, c1, r1, c2, r2, dcol, drow);
  627.         if (!vt->lazy) {
  628.             wbegindrawing(vt->win);
  629.             if (drow < 0)
  630.                 werase(c1, r2+drow, c2, r2);
  631.             if (drow > 0)
  632.                 werase(c1, r1, c2, r1+drow);
  633.             if (dcol < 0)
  634.                 werase(c2+dcol, r1, c2, r2);
  635.             if (dcol > 0)
  636.                 werase(c1, r1, c1+dcol, r2);
  637.             wenddrawing(vt->win);
  638.         }
  639.     }
  640. }
  641.  
  642. /* Execute delayed scrolling.
  643.    Don't call from within drawproc: wscroll while drawing is BAD. */
  644.  
  645. void
  646. vtsync(vt)
  647.     VT *vt;
  648. {
  649.     if (vt->toscroll != 0) {
  650.         int scr_top= vt->scr_top;
  651.         if (scr_top == vt->topterm)
  652.             scr_top= 0;
  653.         wscroll(vt->win,
  654.             0, scr_top * vt->cheight,
  655.             vt->cols * vt->cwidth, vt->scr_bot * vt->cheight,
  656.             0, vt->toscroll * vt->cheight);
  657.         vt->toscroll= 0;
  658.     }
  659. }
  660.